package com.tlgen.utils;

import com.google.common.collect.Lists;
import com.tlgen.annotation.ConfigFieldProperties;
import com.tlgen.annotation.Value;
import com.tlgen.model.FieldVO;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static com.tlgen.utils.YamlUtils.*;

/**
 * 反射工具类
 */
public class ReflectUtils {

    /**
     * 根据对象的属性名获取其属性值
     * @param clazz
     * @param fieldName
     * @return
     */
    public static String getFieldValue(Class clazz, String fieldName) {
        // 1.根据属性名称就可以获取其get方法
        String getMethodName = "get"
                + fieldName.substring(0, 1).toUpperCase()
                + fieldName.substring(1);
        Object obj = null;
        try {
            Class<?> aClass = Class.forName(clazz.getName());
            try {
                obj = aClass.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            // get 方法都是 public 的且无参数
            Method m= clazz.getMethod(getMethodName);
            //3 通过方法的反射操作方法
            Object value = m.invoke(obj);
            return String.valueOf(value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取类中属性和值
     *
     * @param clazz
     * @return
     */
    public static List<FieldVO> getFieldName(Class clazz) {
        List<FieldVO> fieldList = Lists.newArrayList();
        for (Field field : clazz.getDeclaredFields()) {
            // 设置对象的访问权限, 保证对 private 的属性的访问
            field.setAccessible(true);
            FieldVO vo = new FieldVO();
            vo.setFieldName(field.getName());
            String fieldValue = getFieldValue(clazz, field.getName());
            vo.setFieldValue(fieldValue);
            fieldList.add(vo);
        }
        return fieldList;
    }

    /**
     * 获取属性上注解, 并设置成 yml 配置中属性对应的值
     * @param clazz
     * @param field
     */
    public static Object setAnnoFieldValue(Class clazz, Field field) {
        Object obj = null;
        try {
            obj = clazz.newInstance();
            Value value = field.getAnnotation(Value.class);
            // 如果属性上带有 @Value 注解
            if (null != value) {
                String fieldAnnoValue = value.value();
                if (null != fieldAnnoValue) {
                    fieldAnnoValue = fieldAnnoValue.substring(2, fieldAnnoValue.length() - 1);
                    String[] split = fieldAnnoValue.split("\\.");
                    // 先读取本地
                    Object localPropertiesValue = getLocalConfigProperties(Arrays.asList(split));
                    // 再读取项目 resource 目录下, 优先级 resource > 本地
                    Object propertiesValue = getConfigProperties(Arrays.asList(split));
                    field.setAccessible(true);
                    field.set(obj, Objects.isNull(propertiesValue) ? String.valueOf(localPropertiesValue): String.valueOf(propertiesValue));
                }
            } else {
                // 直接拿属性值作为键 key
                String fieldName = field.getName();
                ConfigFieldProperties annotation = (ConfigFieldProperties) clazz.getAnnotation(ConfigFieldProperties.class);
                if (null != annotation) {
                    // 获取配置前缀
                    String prefix = annotation.prefix();
                    // 先读取本地
                    Object localPropertiesValue = getLocalConfigProperties(prefix, fieldName);
                    // 再读取项目 resource 目录下, 优先级 resource > 本地
                    Object propertiesValue = getConfigProperties(prefix, fieldName);
                    field.setAccessible(true);
                    field.set(obj, Objects.isNull(propertiesValue) ? String.valueOf(localPropertiesValue): String.valueOf(propertiesValue));
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 获取属性上注解, 并设置成 yml 配置中属性对应的值
     * @param obj 已修改过的 obj 对象
     * @param field
     */
    public static void setAnnoFieldValue(Object obj, Field field) {
        try {
            Value value = field.getAnnotation(Value.class);
            // 如果属性上带有 @Value 注解
            if (null != value) {
                String fieldAnnoValue = value.value();
                if (null != fieldAnnoValue) {
                    fieldAnnoValue = fieldAnnoValue.substring(2, fieldAnnoValue.length() - 1);
                    String[] split = fieldAnnoValue.split("\\.");
                    // 先读取本地
                    Object localPropertiesValue = getLocalConfigProperties(Arrays.asList(split));
                    // 再读取项目 resource 目录下, 优先级 resource > 本地
                    Object propertiesValue = getConfigProperties(Arrays.asList(split));
                    field.setAccessible(true);
                    field.set(obj, Objects.isNull(propertiesValue) ? String.valueOf(localPropertiesValue): String.valueOf(propertiesValue));
                }
            } else {
                // 直接拿属性值作为键 key
                String fieldName = field.getName();
                ConfigFieldProperties annotation = obj.getClass().getAnnotation(ConfigFieldProperties.class);
                if (null != annotation) {
                    // 获取配置前缀
                    String prefix = annotation.prefix();
                    // 先读取本地
                    Object localPropertiesValue = getLocalConfigProperties(prefix, fieldName);
                    // 再读取项目 resource 目录下, 优先级 resource > 本地
                    Object propertiesValue = getConfigProperties(prefix, fieldName);
                    field.setAccessible(true);
                    field.set(obj, Objects.isNull(propertiesValue) ? String.valueOf(localPropertiesValue): String.valueOf(propertiesValue));
                }
            }
//            if (null != value) {
//                String fieldAnnoValue = value.value();
//                if (null != fieldAnnoValue) {
//                    fieldAnnoValue = fieldAnnoValue.substring(2, fieldAnnoValue.length() - 1);
//                    String[] split = fieldAnnoValue.split("\\.");
//                    // 先读取本地
//                    Object localPropertiesValue = getLocalConfigProperties(Arrays.asList(split));
//                    // 再读取项目 resource 目录下, 优先级 resource > 本地
//                    Object propertiesValue = getConfigProperties(Arrays.asList(split));
//                    field.setAccessible(true);
//                    field.set(obj, Objects.isNull(propertiesValue) ? String.valueOf(localPropertiesValue): String.valueOf(propertiesValue));
//                }
//
//            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据类型和属性名创建 Field 对象
     * @param clazz
     * @param fieldName
     * @return
     */
    public static Field getFiledInstance(Class clazz, String fieldName) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            return field;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据类型获取类的名称
     * @param clazz
     * @return
     */
    public static String getClassName(Class clazz) {
        String name = clazz.getName();
        String[] strings = name.split("\\.");
        return strings[strings.length - 1];
    }

}
